#include "test_common.h"

using namespace std;
using namespace boost;

static char userAgent_[1024];


void analyse_useragent(const PacketInfo *pPkt, MySQL *sqlConn)
{
	memset(userAgent_,0,1024);
	std::string regstr = "\r\nUser-Agent:\\s(.*?)\r\n";
	boost::regex expression(regstr);

	boost::cmatch matchedStr;
	const char *begin = pPkt->body;
	const char *end = pPkt->body + pPkt->bodyLen;

	if(boost::regex_search(begin, end, matchedStr, expression))
	{
		u_short tmplen=matchedStr[1].length();
		if(tmplen<1024)
		{
			char *tmp= new char[tmplen+1];
			tmp[tmplen]=0;
			memcpy(tmp, matchedStr[1].first, tmplen);
			sprintf(userAgent_,"%s",tmp);
			delete tmp;

			analyse_research_info(pPkt, sqlConn);
		}
	}
}

void  analyse_research_info(const PacketInfo *pktInfo, MySQL *sqlConn)
{
	string os, browser;
	if (get_research_info_os(os))
	{
		store_research_info(pktInfo, 601, os.c_str(), sqlConn);
	}

	if (get_research_info_browser(browser))
	{
		store_research_info(pktInfo, 602, browser.c_str(), sqlConn);
	}
}


bool get_research_info_os(string &os)
{
	if (is_os_windows(os))
	{
		return true;
	}
	if (is_os_linux(os))
	{
		return true;
	}
	if (is_os_mac(os))
	{
		return true;
	}

	return false;
}

bool get_research_info_browser(string &browser)
{
	if (is_browser_qqbrowser(browser))
	{
		return true;
	}
	if (is_browser_tencenttraveler(browser))
	{
		return true;
	}
	if (is_browser_maxthon(browser))
	{
		return true;
	}
	if (is_browser_360se(browser))
	{
		return true;
	}
	if (is_browser_sogou(browser))
	{
		return true;
	}
	if (is_browser_theworld(browser))
	{
		return true;
	}
	if (is_browser_opera(browser))
	{
		return true;
	}
	if (is_browser_konqueror(browser))
	{
		return true;	
	}	

	// These judgments must be placed in the final 
	// Best not to change their order
	if (is_browser_chrome(browser))
	{
		return true;
	}
	if (is_browser_safari(browser))
	{
		return true;
	}
	if (is_browser_firefox(browser)) 
	{
		return true;
	}
	if (is_browser_msie(browser))
	{
		return true;
	}

	return false;
}

bool is_os_windows(string &os)
{
	cmatch match;

	if (regex_search(userAgent_, match, regex("Windows NT 5.1")))
	{
		os = "Windows XP";
	}
	else if (regex_search(userAgent_, match, regex("Windows NT 6.1")))
	{
		os = "Windows 7";
	}
	else if (regex_search(userAgent_, match, regex("Windows NT 6.0")))
	{
		os = "Windows Vista";
	}
	else if (regex_search(userAgent_, match, regex("Windows NT 5.2")))
	{
		os = "Windows Server 2003";
	}
	else if (regex_search(userAgent_, match, regex("Windows NT 5.0")))
	{
		os = "Windows 2000";
	}
	else if (regex_search(userAgent_, match, regex("Windows NT")))
	{
		os = "Windows NT";
	}
	else if (regex_search(userAgent_, match, regex("Windows CE")))
	{
		os = "Windows CE";
	}
	else if (regex_search(userAgent_, match, regex("Windows 9x 4.90")))
	{
		os = "Windows Me";
	}
	else if (regex_search(userAgent_, match, regex("Windows 98")))
	{
		os = "Windows 98";
	} 
	else if (regex_search(userAgent_, match, regex("Windows 95"))) 
	{
		os = "Windows 95";
	}
	else
	{
		return false;
	}

	return true;
}

bool is_os_linux(string &os)
{
	cmatch match;	
	if (regex_search(userAgent_, match, regex("Linux")))	
	{
		os = "Linux";
		return true;
	}

	return false;
}

bool is_os_mac(string &os)
{
	cmatch match;
	if (regex_search(userAgent_, match, regex("OS ([\\w]+) like Mac OS X")))
	{
		os = "iPhone OS " + match[1];
		return true;
	}
	if (regex_search(userAgent_, match, regex("Mac OS X ([\\w]+)")))
	{
		os = "Mac OS X " + match[1];
		return true;
	}
	if (regex_search(userAgent_, match, regex("Mac OS X")))
	{
		os = "Mac OS X";
		return true;
	}

	return false;
}

bool is_browser_msie(string &browser)
{
	cmatch match;
	const regex reg("MSIE (\\d+\\.\\d+)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Internet Explorer " + match[1];
		return true; 
	}

	return false;
}

bool is_browser_firefox(string &browser)
{
	cmatch match;
	const regex reg("Firefox/([\\da-zA-Z\\.]+)?");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Firefox " + match[1];
		return true;
	}

	const regex reg1("Firefox");
	if (regex_search(userAgent_, match, reg1))
	{
		browser = "Firefox";
		return true;
	}

	return false;
}

bool is_browser_chrome(string& browser)
{
	cmatch match;
	const regex reg("Chrome/([\\d\\.a-zA-Z]+)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Chrome " + match[1];
		return true;
	}

	const regex reg1("Chrome");
	if (regex_search(userAgent_, match, reg1))
	{
		browser = "Chrome";
		return true;
	}

	return false;
}

bool is_browser_safari(string& browser)
{
	cmatch match;
	const regex reg("Version/([\\d\\.a-zA-Z]+) Safari/[\\d\\.a-zA-Z]+");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Safari " + match[1];
		return true;
	}

	const regex reg1("Version/([\\d\\.a-zA-Z]+) Mobile/[\\d\\.a-zA-Z]+ Safari/[\\d\\.a-zA-Z]+");
	if (regex_search(userAgent_, match, reg1))
	{
		browser = "Safari " + match[1];
		return true;
	}

	const regex reg2("Safari/[\\d\\.a-zA-Z]+");
	if (regex_search(userAgent_, match, reg2))
	{
		browser = "Safari";
		return true;
	}

	return false;
}

bool is_browser_opera(string& browser)
{
	cmatch match;
	const regex reg("Opera/[\\d\\.a-zA-Z]+.*?Version/([\\d\\.a-zA-Z]+)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Opera " + match[1];
		return true;
	}
	
	const regex reg1("Opera[ /]([\\d\\.a-zA-Z]+)");
	if (regex_search(userAgent_, match, reg1))
	{
		browser = "Opera " + match[1];
		return true;
	}

	const regex reg2("Opera");
	if (regex_search(userAgent_, match, reg2))
	{
		browser = "Opera";
		return true;
	}

	return false;
}

bool is_browser_maxthon(string &browser)
{
	cmatch match;
	const regex reg("Maxthon/([\\d\\.a-zA-Z]+)", regex::icase);
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Maxthon " + match[1];
		return true;
	}

	const regex reg1("Maxthon ([\\d\\.a-zA-Z]+)", regex::icase);
	if (regex_search(userAgent_, match, reg1))
	{
		browser = "Maxthon " + match[1];
		return true;
	}

	const regex reg2("Maxthon", regex::icase);
	if (regex_search(userAgent_, match, reg2))
	{
		browser = "Maxthon";
		return true;
	}

	return false;
}

bool is_browser_360se(string &browser)
{
	cmatch match;
	const regex reg("360SE");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "360SE";
		return true;
	}

	return false;
}

bool is_browser_sogou(string &browser)
{
	cmatch match;
	const regex reg("SE (\\d+\\.X)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Sogou " + match[1];
		return true;
	}

	return false;
}

bool is_browser_qqbrowser(string &browser)
{
	cmatch match;
	const regex reg("QQBrowser/([\\d\\.a-zA-Z]+)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "QQBrowser " + match[1];
		return true;
	}

	return false;
}

bool is_browser_tencenttraveler(string &browser)
{
	cmatch match;
	const regex reg("TencentTraveler ([\\d\\.a-zA-Z]+)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "TencentTraveler " + match[1];
		return true;
	}

	return false;
}

bool is_browser_theworld(string &browser)
{
	cmatch match;
	const regex reg("TheWorld");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "TheWorld";
		return true;
	}

	return false;
}

bool is_browser_konqueror(string &browser)
{
	cmatch match;
	const regex reg("Konqueror/([\\d\\.a-zA-Z-]+)");
	if (regex_search(userAgent_, match, reg))
	{
		browser = "Konqueror " + match[1];
		return true;
	}

	return false;
}

void store_research_info(const PacketInfo *pktInfo, const int nType, const char* info, MySQL *sqlConn)
{
	char tmp[256];
	char strMac[20];
	struct in_addr addr;
	string sql;

	int readFlag_ = 0;
	unsigned long clientIp_ = pktInfo->srcIpv4;
	unsigned long serverIp_ = pktInfo->destIpv4;
	unsigned short clientPort_ = pktInfo->srcPort;
	unsigned short serverPort_ = pktInfo->destPort;
	string objectInfo_ = info;
	unsigned char clientMac_[6];
	memcpy(clientMac_, pktInfo->srcMac, 6);
	memset(strMac, 0, 20);
	ParseMac(pktInfo->srcMac, strMac);
	int type_ = nType;
	unsigned long objectId_ = GetObjectId(strMac);

	sql = "insert into research(objectid, readflag, clientip, clientmac, serverip, clientport, serverport, capturetime, osinfo, type)";

	sql += " values(";
	sprintf(tmp, "%lu", objectId_);
	sql += tmp;

	sql += ", ";
	sprintf(tmp, "%d", readFlag_);
	sql += tmp;

	sql += ", \'";
	addr.s_addr = clientIp_;
	sql += inet_ntoa(addr);
	sql += "\'";
	
	sql += ", \'";
	ParseMac(clientMac_, strMac);
	sql += strMac;
	sql += "\'";

	sql += ", \'";
	addr.s_addr = serverIp_;
	sql += inet_ntoa(addr);
	sql += "\'";

	sql += ", ";
	sprintf(tmp, "%d", clientPort_);
	sql += tmp;

	sql += ", ";
	sprintf(tmp, "%d", serverPort_);
	sql += tmp;

	sql += ", ";
	sql += "now()";

	sql += ", \'";
	sql += objectInfo_;
	sql += "\'";

	sql += ", ";
	sprintf(tmp, "%d", type_);
	sql += tmp;
	sql += ")";

	if (sqlConn)
	{
		sqlConn->Insert(&sql);
		cout << "[UserAgent] Data has been insert into the database" << endl;
		AddObjectId (objectId_,strMac);
	}
	else
	{
		cout << "[UserAgent] Not connected to the database" << endl;
	}
}
